<script setup lang="ts">
import { ref, computed, watch } from 'vue';

interface Header {
	key: string;
	value: string;
}

interface QueryParam {
	key: string;
	value: string;
}

const url = ref('https://api.example.com/v1/users');
const method = ref('POST');
const headers = ref<Header[]>([{ key: '', value: '' }]);
const queryParams = ref<QueryParam[]>([{ key: '', value: '' }]);
const requestBody = ref('');
const contentType = ref('application/json');
const timeout = ref('30');
const followRedirects = ref(true);
const verbose = ref(true);
const insecure = ref(true);
const silentOutput = ref(true);

// 错误状态
const urlError = ref('');
const bodyError = ref('');

const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'];

// 解析URL
const parsedUrl = computed(() => {
	try {
		if (!url.value) return null;
		return new URL(url.value);
	} catch (error) {
		return null;
	}
});

// 验证URL格式
const validateUrl = () => {
	if (!url.value) {
		urlError.value = '';
		return;
	}

	try {
		new URL(url.value);
		urlError.value = '';
	} catch (error) {
		urlError.value =
			'请输入有效的URL格式，例如: https://api.example.com/v1/users';
	}
};

// 格式化请求体
const formatRequestBody = () => {
	if (!requestBody.value) {
		bodyError.value = '';
		return;
	}

	try {
		switch (contentType.value) {
			case 'application/json':
				// 尝试解析和格式化JSON
				const parsed = JSON.parse(requestBody.value);
				requestBody.value = JSON.stringify(parsed, null, 2);
				bodyError.value = '';
				break;

			case 'application/xml':
				// 简单的XML格式化（移除多余空格）
				requestBody.value = requestBody.value.trim();
				bodyError.value = '';
				break;

			case 'application/x-www-form-urlencoded':
				// 验证表单数据格式
				const pairs = requestBody.value.split('&');
				for (const pair of pairs) {
					if (pair && !pair.includes('=')) {
						bodyError.value =
							'表单数据格式应为: key1=value1&key2=value2';
						return;
					}
				}
				bodyError.value = '';
				break;

			default:
				bodyError.value = '';
		}
	} catch (error) {
		if (contentType.value === 'application/json') {
			bodyError.value = 'JSON格式无效，请检查语法';
		} else {
			bodyError.value = '格式验证失败';
		}
	}
};

// 监听内容类型变化，重新格式化
watch(contentType, () => {
	formatRequestBody();
});

// 监听请求体变化，延迟验证
let formatTimeout: NodeJS.Timeout;
watch(requestBody, () => {
	clearTimeout(formatTimeout);
	formatTimeout = setTimeout(() => {
		formatRequestBody();
	}, 500);
});

const generatedCommand = computed(() => {
	let command = 'curl';

	// 使用解析后的URL
	if (parsedUrl.value) {
		command += ` "${parsedUrl.value.toString()}"`;
	} else {
		command += ` "${url.value}"`;
	}

	// 添加请求方法
	if (method.value !== 'GET') {
		command += ` -X ${method.value}`;
	}

	// 添加请求头
	const validHeaders = headers.value.filter(
		(header) => header.key && header.value
	);
	validHeaders.forEach((header) => {
		command += ` -H "${header.key}: ${header.value}"`;
	});

	// 添加内容类型
	if (['POST', 'PUT', 'PATCH'].includes(method.value) && requestBody.value) {
		command += ` -H "Content-Type: ${contentType.value}"`;
	}

	// 添加请求体
	if (['POST', 'PUT', 'PATCH'].includes(method.value) && requestBody.value) {
		command += ` -d '${requestBody.value}'`;
	}

	// 添加超时
	if (timeout.value && timeout.value !== '30') {
		command += ` --max-time ${timeout.value}`;
	}

	// 添加重定向
	if (followRedirects.value) {
		command += ' -L';
	}

	// 添加详细输出
	if (verbose.value) {
		command += ' -v';
	}

	// 添加不安全选项
	if (insecure.value) {
		command += ' -k';
	}

	// 添加静默输出选项
	if (silentOutput.value) {
		command += ' -o /dev/null';
	}

	return command;
});

const addHeader = () => {
	headers.value.push({ key: '', value: '' });
};

const removeHeader = (index: number) => {
	if (headers.value.length > 1) {
		headers.value.splice(index, 1);
	}
};

const addQueryParam = () => {
	queryParams.value.push({ key: '', value: '' });
};

const removeQueryParam = (index: number) => {
	if (queryParams.value.length > 1) {
		queryParams.value.splice(index, 1);
	}
};

const copyCommand = () => {
	navigator.clipboard.writeText(generatedCommand.value);
};

// 初始化时验证URL
validateUrl();
</script>

<template>
	<c-card>
		<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
			<!-- 左侧配置面板 -->
			<div class="space-y-6">
				<!-- 基本配置 -->
				<div class="space-y-4">
					<h3 class="text-lg font-semibold">基本配置</h3>

					<c-input-text
						v-model:value="url"
						label="URL"
						placeholder="https://api.example.com/v1/users"
						@blur="validateUrl" />

					<c-select
						v-model:value="method"
						:options="methods.map((m) => ({ label: m, value: m }))"
						label="请求方法" />
				</div>

				<!-- 查询参数 -->
				<div class="space-y-4">
					<div class="flex justify-between items-center">
						<h3 class="text-lg font-semibold">查询参数</h3>
						<c-button size="small" @click="addQueryParam">
							添加参数
						</c-button>
					</div>

					<div
						v-for="(param, index) in queryParams"
						:key="index"
						class="flex gap-2 items-end">
						<c-input-text
							v-model:value="param.key"
							placeholder="参数名"
							class="flex-1" />
						<c-input-text
							v-model:value="param.value"
							placeholder="参数值"
							class="flex-1" />
						<c-button
							v-if="queryParams.length > 1"
							size="small"
							type="error"
							@click="removeQueryParam(index)">
							删除
						</c-button>
					</div>
				</div>

				<!-- 请求头 -->
				<div class="space-y-4">
					<div class="flex justify-between items-center">
						<h3 class="text-lg font-semibold">请求头</h3>
						<c-button size="small" @click="addHeader">
							添加请求头
						</c-button>
					</div>

					<div
						v-for="(header, index) in headers"
						:key="index"
						class="flex gap-2 items-end">
						<c-input-text
							v-model:value="header.key"
							placeholder="Header 名称"
							class="flex-1" />
						<c-input-text
							v-model:value="header.value"
							placeholder="Header 值"
							class="flex-1" />
						<c-button
							v-if="headers.length > 1"
							size="small"
							type="error"
							@click="removeHeader(index)">
							删除
						</c-button>
					</div>
				</div>

				<!-- 请求体 -->
				<div
					v-if="['POST', 'PUT', 'PATCH'].includes(method)"
					class="space-y-4">
					<h3 class="text-lg font-semibold">请求体</h3>

					<c-select
						v-model:value="contentType"
						:options="[
							{
								label: 'application/json',
								value: 'application/json'
							},
							{
								label: 'application/x-www-form-urlencoded',
								value: 'application/x-www-form-urlencoded'
							},
							{ label: 'text/plain', value: 'text/plain' },
							{
								label: 'application/xml',
								value: 'application/xml'
							}
						]"
						label="内容类型" />

					<div class="space-y-2">
						<c-input-text
							v-model:value="requestBody"
							label="请求体"
							type="textarea"
							placeholder="请输入请求体内容"
							:rows="6" />

						<!-- 格式提示 -->
						<div
							v-if="contentType === 'application/json'"
							class="text-xs text-gray-500">
							支持JSON格式，将自动格式化
						</div>
						<div
							v-else-if="
								contentType ===
								'application/x-www-form-urlencoded'
							"
							class="text-xs text-gray-500">
							格式：key1=value1&key2=value2
						</div>
					</div>
				</div>

				<!-- 高级选项 -->
				<div class="space-y-4">
					<h3 class="text-lg font-semibold">高级选项</h3>

					<c-input-text
						v-model:value="timeout"
						label="超时时间（秒）"
						type="number"
						placeholder="30" />

					<div class="space-y-2">
						<c-label>
							<n-checkbox v-model:checked="followRedirects">
								跟随重定向
							</n-checkbox>
						</c-label>

						<c-label>
							<n-checkbox v-model:checked="verbose">
								详细输出
							</n-checkbox>
						</c-label>

						<c-label>
							<n-checkbox v-model:checked="insecure">
								忽略 SSL 证书验证
							</n-checkbox>
						</c-label>

						<c-label>
							<n-checkbox v-model:checked="silentOutput">
								静默输出 (-o /dev/null)
							</n-checkbox>
						</c-label>
					</div>
				</div>
			</div>

			<!-- 右侧生成的命令 -->
			<div class="space-y-4">
				<div class="flex justify-between items-center">
					<h3 class="text-lg font-semibold">生成的 curl 命令</h3>
					<c-button @click="copyCommand">复制命令</c-button>
				</div>

				<c-input-text
					:value="generatedCommand"
					readonly
					type="textarea"
					:rows="10"
					placeholder="curl 命令将在这里生成..." />

				<!-- 命令预览 -->
				<div class="bg-gray-100 dark:bg-gray-800 p-4 rounded-lg">
					<h4 class="font-medium mb-2">命令预览：</h4>
					<pre class="text-sm overflow-x-auto">{{
						generatedCommand
					}}</pre>
				</div>

				<!-- 错误提示 -->
				<div v-if="urlError || bodyError" class="space-y-2">
					<div
						v-if="urlError"
						class="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
						<div class="text-sm text-red-600 dark:text-red-400">
							<strong>URL错误：</strong>
							{{ urlError }}
						</div>
					</div>

					<div
						v-if="bodyError"
						class="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
						<div class="text-sm text-red-600 dark:text-red-400">
							<strong>请求体错误：</strong>
							{{ bodyError }}
						</div>
					</div>
				</div>
			</div>
		</div>
	</c-card>
</template>

<style lang="less" scoped>
.grid {
	display: grid;
}

.grid-cols-1 {
	grid-template-columns: repeat(1, minmax(0, 1fr));
}

.grid-cols-2 {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.gap-2 {
	gap: 0.5rem;
}

.gap-6 {
	gap: 1.5rem;
}

.space-y-2 > * + * {
	margin-top: 0.5rem;
}

.space-y-4 > * + * {
	margin-top: 1rem;
}

.space-y-6 > * + * {
	margin-top: 1.5rem;
}

.flex {
	display: flex;
}

.flex-1 {
	flex: 1 1 0%;
}

.items-end {
	align-items: flex-end;
}

.items-center {
	align-items: center;
}

.justify-between {
	justify-content: space-between;
}

.text-lg {
	font-size: 1.125rem;
	line-height: 1.75rem;
}

.font-semibold {
	font-weight: 600;
}

.font-medium {
	font-weight: 500;
}

.text-sm {
	font-size: 0.875rem;
	line-height: 1.25rem;
}

.text-xs {
	font-size: 0.75rem;
	line-height: 1rem;
}

.text-gray-500 {
	color: #6b7280;
}

.overflow-x-auto {
	overflow-x: auto;
}

.p-3 {
	padding: 0.75rem;
}

.p-4 {
	padding: 1rem;
}

.mb-2 {
	margin-bottom: 0.5rem;
}

.rounded-lg {
	border-radius: 0.5rem;
}

.bg-gray-100 {
	background-color: #f3f4f6;
}

.bg-red-50 {
	background-color: #fef2f2;
}

.border-red-200 {
	border-color: #fecaca;
}

.text-red-600 {
	color: #dc2626;
}

.dark .bg-gray-800 {
	background-color: #1f2937;
}

.dark .bg-red-900\/20 {
	background-color: rgb(127 29 29 / 0.2);
}

.dark .border-red-800 {
	border-color: #991b1b;
}

.dark .text-red-400 {
	color: #f87171;
}

@media (min-width: 768px) {
	.md\\:grid-cols-2 {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
</style> 